/**
 *
 */

#ifndef STEXT_H_
#define STEXT_H_

#include "sutil.h"


#define MAX_INFO_KEYLEN		32
#define MAX_INFO_VALLEN		512

typedef struct KVPair{
	char akey[MAX_INFO_KEYLEN];
	char avalue[MAX_INFO_VALLEN];
	struct KVPair *pnext;
} KV;

void freeKVPair(struct KVPair *_pKv) {

	if(_pKv == NULL) {
		return;
	}
	struct KVPair *pkv = _pKv;
	while((_pKv=_pKv->pnext)!=NULL) {
		free(pkv);
		pkv = _pKv;
	}
	free(pkv);
}

struct KVPair* api_lineToKV(const char *_pTxt, const char *_pDeli) {

	if( _pTxt == NULL)
		return NULL;

	struct KVPair *pKv = (struct KVPair *)MALLOC(sizeof(struct KVPair));
	pKv->pnext = NULL;

	int isKey	= 1;
	int isVal	= 0;
	int kcount	= 0;
	int vcount	= 0;
	int dumpKey	= 0;
	while(*_pTxt) {
		if(api_isDelimiter(*_pTxt, _pDeli)) {
			if(isKey == 1 && kcount == 0) {
				++_pTxt;
				continue;
			}
			if(isKey == 1 && kcount > 0){
				pKv->akey[kcount] = '\0';
				isKey = 0;
			}
			if(isKey == 0 && isVal == 0 && vcount == 0) {
				dumpKey = 0;
				++_pTxt;
				continue;
			}
			if(isKey == 0 && isVal == 1 && vcount > 0) {
				pKv->avalue[vcount] = '\0';
				break;
			}
		} else {
			if(isKey == 1) {
				pKv->akey[kcount++] = *_pTxt;
				if(kcount == MAX_INFO_KEYLEN) {
					pKv->akey[kcount-1] = '\0';
					isKey = 0;
					dumpKey = 1;
				}
			} else {
				if(dumpKey == 1) {
					++_pTxt;
					continue;
				}
				isVal = 1;
				pKv->avalue[vcount++] = *_pTxt;
				if(vcount == MAX_INFO_VALLEN){
					pKv->avalue[vcount-1] = '\0';
					isVal = 0;
					break;
				}
			}
		}

		++_pTxt;
	}

	api_stripSpace(pKv->akey);
	api_stripSpace(pKv->avalue);

	if(strlen(pKv->akey) == 0) {
		free(pKv);
		return NULL;
	}
	return pKv;
}

struct KVPair* api_textToKV(const char *_pTxt, const char *_pDeli) {
	if(_pTxt == NULL)
		return NULL;
	struct KVPair *pkv	= NULL;
	struct KVPair *kvhead	= NULL;
	struct KVPair *newkv	= NULL;

	char buf[MAX_BUF_SIZE];
	bzero(buf, MAX_BUF_SIZE);
	char *pnext = (char *)_pTxt;
	while( *pnext != '\0') {
		pnext = api_getCharLine(pnext, buf, MAX_BUF_SIZE);
		newkv = api_lineToKV(buf, _pDeli);
		if(newkv == NULL) {
			continue;
		}
		if(pkv == NULL) {
			kvhead	= newkv;
			pkv	= newkv;
		} else {
			pkv->pnext = newkv;
			pkv = newkv;
		}
	}

	return kvhead;
}


typedef struct ListNode {
	int type;
	char avalue	[MAX_INFO_VALLEN];
	struct ListNode	*pprev;
	struct ListNode	*pnext;
} LNode;

typedef struct ListNode* pLNode;

/* if the value is too long, it may need to
 * nodes or more to store it. LEAD means it
 * is the first segment in a value, and FLLW
 * means it is not the first segment*/
#define LNODE_TYPE_LEAD		2
#define LNODE_TYPE_FLLW		1

void freeListNode(LNode *_pLNode) {
	if( _pLNode == NULL)
		return;
	struct ListNode *pNode = _pLNode;
	while(( _pLNode = _pLNode->pnext) != NULL) {
		free(pNode);
		pNode =  _pLNode;
	}
	free(pNode);
}

struct ListNode * textToList(const char *_pLine, const char *_pDeli) {

	pLNode phead	= NULL;
	pLNode pcurr	= NULL;
	
	int vcount	= 0;
	/* type = 0, means it is the begining of a value, so the LNode.type
	 * should be LEAD, else FLLW*/
	int type	= 0;
	char buf[MAX_INFO_VALLEN];
	bzero(buf, MAX_INFO_VALLEN);
	while(*_pLine) {
		if(api_isDelimiter(*_pLine, _pDeli)) {
			if(vcount == 0) {
				++_pLine;
				type = 0;
				continue;
			} else {
				if(phead == NULL) {
					phead =  (pLNode)MALLOC(sizeof(LNode) * sizeof(char));
					if(phead == NULL) {
						return NULL;
					}
					pcurr = phead;
				} else {
					pcurr->pnext = (pLNode)MALLOC(sizeof(LNode) * sizeof(char));
					if(pcurr->pnext == NULL) {
						freeListNode(phead);
						return NULL;
					}
					pcurr->pnext->pprev = pcurr;
					pcurr = pcurr->pnext;
				}
				buf[vcount] ='\0';
				memcpy(pcurr->avalue, buf, sizeof(buf));
				vcount = 0;
				if(type == 1) {
					pcurr->type = LNODE_TYPE_FLLW;
					type = 0;
				} else {
					pcurr->type = LNODE_TYPE_LEAD;
				}
			}
		} else {
			buf[vcount++] = *_pLine;
			/* the case when a single node can not store the whole value */
			if(vcount == MAX_INFO_VALLEN-1) {
				buf[vcount] = '\0';
				memcpy(pcurr->avalue, buf, MAX_INFO_VALLEN);
				if(type == 0) {
					pcurr->type = LNODE_TYPE_LEAD;
				} else {
					pcurr->type = LNODE_TYPE_FLLW;
				}
				vcount = 0;
				type = 1;
			} 
		}


		++_pLine;
	}

	/* the case when _pLine meets the end of a string, but not the 
	 * delimmiter, since it is not delimmiter, no action will be
	 * taken to pack the string into KV structure. So we need to 
	 * packe it by ourselves. */
	if(phead == NULL) {
		phead =  (pLNode)MALLOC(sizeof(LNode) * sizeof(char));
		if(phead == NULL) {
			return NULL;
		}
		pcurr = phead;
	} else {
		pcurr->pnext = (pLNode)MALLOC(sizeof(LNode) * sizeof(char));
		if(pcurr->pnext == NULL) {
			freeListNode(phead);
			return NULL;
		}
		pcurr->pnext->pprev = pcurr;
		pcurr = pcurr->pnext;
	}
	buf[vcount] = '\0';
	memcpy(pcurr->avalue, buf, sizeof(buf));
	if(type == 1) {
		pcurr->type = LNODE_TYPE_FLLW;
		type = 0;
	} else {
		pcurr->type = LNODE_TYPE_LEAD;
	}
	vcount = 0;
	
	return phead;

}




#endif /* STEXT_H_ */
